import { isArray } from '@/framework/utils/is';
import axios from 'axios';
import { getToken } from '@/framework/utils/auth';
import { RouteRecordRaw } from 'vue-router';

/**
 * @description 获取localStorage
 * @param {String} key Storage名称
 * @return string
 */
export function localGet(key: string): string {
  const value = window.localStorage.getItem(key) || '';
  try {
    return JSON.parse(window.localStorage.getItem(key) as string);
  } catch (error) {
    return value;
  }
}

/**
 * @description 存储localStorage
 * @param {String} key Storage名称
 * @param {Any} value Storage值
 * @return void
 */
export function localSet(key: string, value: string | boolean | number | [] | null | undefined): void {
  window.localStorage.setItem(key, JSON.stringify(value));
}

/**
 * @description 清除localStorage
 * @param {String} key Storage名称
 * @return void
 */
export function localRemove(key: string): void {
  window.localStorage.removeItem(key);
}

/**
 * @description 清除所有localStorage
 * @return void
 */
export function localClear(): void {
  window.localStorage.clear();
}

/**
 * @description 判断数据类型
 * @param {Any} val 需要判断类型的数据
 * @return string
 */
export function isType(val: string | boolean | number | [] | null | undefined): string {
  if (val === null) return 'null';
  if (typeof val !== 'object') return typeof val;
  else
    return Object.prototype.toString.call(val).slice(8, -1).toLocaleLowerCase();
}

/**
 * @description 生成唯一 uuid
 * @return string
 */
export function generateUUID(): string {
  if (typeof crypto === 'object') {
    if (typeof crypto.randomUUID === 'function') {
      return crypto.randomUUID();
    }
    if (
      typeof crypto.getRandomValues === 'function' &&
      typeof Uint8Array === 'function'
    ) {
      const callback = (c: string): string => {
        const num = Number(c);
        return (
          num ^
          (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))
        ).toString(16);
      };
      return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback);
    }
  }
  let timestamp = new Date().getTime();
  let performanceNow =
    (typeof performance !== 'undefined' &&
      performance.now &&
      performance.now() * 1000) ||
    0;
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    let random = Math.random() * 16;
    if (timestamp > 0) {
      random = (timestamp + random) % 16 | 0;
      timestamp = Math.floor(timestamp / 16);
    } else {
      random = (performanceNow + random) % 16 | 0;
      performanceNow = Math.floor(performanceNow / 16);
    }
    return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16);
  });
}

/**
 * 判断两个对象是否相同
 * @param a 要比较的对象一
 * @param b 要比较的对象二
 * @returns 相同返回 true，反之则反
 */
// export function isObjectValueEqual(
//   a: Record<string, unknown>,
//   b: Record<string, unknown>
// ): boolean {
//   if (!a || !b) return false;
//   const aProps = Object.getOwnPropertyNames(a);
//   const bProps = Object.getOwnPropertyNames(b);
//   if (aProps.length != bProps.length) return false;
//   for (let i = 0; i < aProps.length; i++) {
//     const propName = aProps[i];
//     const propA = a[propName];
//     const propB = b[propName];
//     if (!b.ObjecthasOwnProperty(propName)) return false;
//     if (propA instanceof Object) {
//       if (!isObjectValueEqual(propA, propB)) return false;
//     } else if (propA !== propB) {
//       return false;
//     }
//   }
//   return true;
// }
export function isObjectValueEqual(
  a: Record<string, unknown>,
  b: Record<string, unknown>
): boolean {
  if (!a || !b) return false;
  const aProps = Object.getOwnPropertyNames(a);
  const bProps = Object.getOwnPropertyNames(b);
  if (aProps.length !== bProps.length) return false;
  for (let i = 0; i < aProps.length; i++) {
    const propName = aProps[i];
    const propA = a[propName];
    const propB = b[propName];
    // 修复点1: 替换为正确的属性检查方法
    if (!(propName in b)) return false;
    // 修复点2: 使用 typeof 操作符而不是 instanceof Object 来检查是否是对象
    if (typeof propA === 'object' && propA !== null) {
      if (!isObjectValueEqual(propA as Record<string, unknown>, propB as Record<string, unknown>)) return false;
    } else if (propA !== propB) {
      return false;
    }
  }
  return true;
}

/**
 * @description 生成随机数
 * @param {Number} min 最小值
 * @param {Number} max 最大值
 * @return number
 */
export function randomNum(min: number, max: number): number {
  const num = Math.floor(Math.random() * (min - max) + max);
  return num;
}

/**
 * @description 获取当前时间对应的提示语
 * @return string
 */
export function getTimeState(): string {
  // 获取当前时间
  const timeNow = new Date();
  // 获取当前小时
  const hours = timeNow.getHours();
  // 判断当前时间段
  if (hours >= 6 && hours <= 10) return `早上好 ⛅`;
  if (hours >= 10 && hours <= 14) return `中午好 🌞`;
  if (hours >= 14 && hours <= 18) return `下午好 🌞`;
  if (hours >= 18 && hours <= 24) return `晚上好 🌛`;
  if (hours >= 0 && hours <= 6) return `凌晨好 🌛`;
  return ''
}

/**
 * @description 获取浏览器默认语言
 * @return string
 */
export function getBrowserLang(): string {
  const browserLang = navigator.language || '';
  let defaultBrowserLang = '';
  if (
    browserLang.toLowerCase() === 'cn' ||
    browserLang.toLowerCase() === 'zh' ||
    browserLang.toLowerCase() === 'zh-cn'
  ) {
    defaultBrowserLang = 'zh';
  } else {
    defaultBrowserLang = 'en';
  }
  return defaultBrowserLang;
}

/**
 * @description 递归查询当前路由所对应的路由
 * @param {Array} menuList 所有菜单列表
 * @param {String} path 当前访问地址
 * @return array
 */
export function filterCurrentRoute(menuList: RouteRecordRaw[], path: string): RouteRecordRaw {
  let result = {};
  for (const item of menuList) {
    if (item.path === path) return item;
    if (item.children) {
      const res = filterCurrentRoute(item.children, path);
      if (Object.keys(res).length) result = res;
    }
  }
  return result as RouteRecordRaw;
}

/**
 * @description 扁平化数组对象(主要用来处理路由菜单)
 * @param {Array} menuList 所有菜单列表
 * @return array
 */
export function getFlatArr(menuList: RouteRecordRaw[]): RouteRecordRaw[] {
  const newMenuList: RouteRecordRaw[] = JSON.parse(JSON.stringify(menuList));
  return newMenuList.reduce(
    (pre: RouteRecordRaw[], current: RouteRecordRaw) => {
      let flatArr = [...pre, current];
      if (current.children)
        flatArr = [...flatArr, ...getFlatArr(current.children)];
      return flatArr;
    },
    []
  );
}

/**
 * @description 使用递归，过滤需要缓存的路由（暂时没有使用）
 * @param {Array} menuList 所有菜单列表
 * @param {Array} cacheArr 缓存的路由菜单 name ['**','**']
 * @return array
 * */
export function getKeepAliveRouterName(
  menuList: RouteRecordRaw[],
  keepAliveArr: string[] = []
): string[] {
  menuList.forEach(item => {
    if (item.meta?.isKeepAlive && item.name) {
      keepAliveArr.push(item.name as string);
    }
    if (item.children?.length) {
      getKeepAliveRouterName(item.children, keepAliveArr);
    }
  });
  return keepAliveArr;
}

/**
 * @description 使用递归，过滤出需要渲染在左侧菜单的列表（剔除 isHide == true 的菜单）
 * @param {Array} menuList 所有菜单列表
 * @return array
 * */
export function getShowMenuList(menuList: RouteRecordRaw[]): RouteRecordRaw[] {
  const newMenuList: RouteRecordRaw[] = JSON.parse(JSON.stringify(menuList));
  return newMenuList.filter(item => {
    item.children?.length && (item.children = getShowMenuList(item.children));
    return !item.meta?.isHide;
  });
}

/**
 * @description 使用递归处理路由菜单 path，生成一维数组(第一版本地路由鉴权会用到)
 * @param {Array} menuList 所有菜单列表
 * @param {Array} menuPathArr 菜单地址的一维数组 ['**','**']
 * @return array
 */
export function getMenuListPath(
  menuList: RouteRecordRaw[],
  menuPathArr: string[] = []
): string[] {
  menuList.forEach((item: RouteRecordRaw) => {
    typeof item === 'object' && item.path && menuPathArr.push(item.path);
    item.children?.length && getMenuListPath(item.children, menuPathArr);
  });
  return menuPathArr;
}

/**
 * @description 递归找出所有面包屑存储到 pinia/vuex 中
 * @param {Array} menuList 所有菜单列表
 * @param {Object} result 输出的结果
 * @param {Array} parent 父级菜单
 * @returns object
 */
// export const getAllBreadcrumbList = (
//   menuList: RouteRecordRaw[],
//   result: Record<string, any> = {},
//   parent = []
// ): RouteRecordRaw => {
//   for (const item of menuList) {
//     result[item.path] = [...parent, item];
//     if (item.children)
//       getAllBreadcrumbList(item.children, result, result[item.path]);
//   }
//   return result;
// };
interface SimplifiedRouteRecordRaw {
  path: string;
  children?: SimplifiedRouteRecordRaw[];
  // ...其他可能需要的属性
}

// 注意：我们仍然返回Record<string, any>，但调用方需要知道如何处理这个类型
// export const getAllBreadcrumbList = (
//   menuList: SimplifiedRouteRecordRaw[],
//   result: Record<string, SimplifiedRouteRecordRaw> = {},
//   // parent = []
//   parent: SimplifiedRouteRecordRaw[] = []
// ): Record<string, SimplifiedRouteRecordRaw> => {
//   for (const item of menuList) {
//     // 假设item.path和item.children是存在的，并且符合我们的类型
//     result[item.path] = [...parent, { path: item.path, children: item.children }];
//     if (item.children)
//       getAllBreadcrumbList(item.children, result, result[item.path]);
//   }
//   return result;
// };
export const getAllBreadcrumbList = (
  menuList: SimplifiedRouteRecordRaw[],
  result: Record<string, SimplifiedRouteRecordRaw[]> = {},
  parent: SimplifiedRouteRecordRaw[] = []
): Record<string, SimplifiedRouteRecordRaw[]> => {
  for (const item of menuList) {
    // 假设item.path和item.children是存在的，并且符合我们的类型
    result[item.path] = [...parent, { path: item.path, ...(item.children ? { children: item.children } : {}) }];
    if (item.children)
      getAllBreadcrumbList(item.children, result, [...parent, { path: item.path, children: item.children }]);
  }
  return result;
};

/**
 * @description 格式化表格单元格默认值(el-table-column)
 * @param {Number} row 行
 * @param {Number} col 列
 * @param {String} callValue 当前单元格值
 * @return string
 * */
export function defaultFormat<T>(row: number, col: number, callValue: T): string {
  // 如果当前值为数组,使用 / 拼接（根据需求自定义）
  if (isArray(callValue))
    return callValue.length ? callValue.join(' / ') : '--';
  return callValue as string ?? '--';
}

/**
 * @description 处理无数据情况
 * @param {String} callValue 需要处理的值
 * @return string
 * */
export function formatValue<T>(callValue: T): string {
  // 如果当前值为数组,使用 / 拼接（根据需求自定义）
  if (isArray(callValue))
    return callValue.length ? callValue.join(' / ') : '--';
  return callValue as string ?? '--';
}

/**
 * @description 处理 prop 为多级嵌套的情况(列如: prop:user.name)
 * @param {Object} row 当前行数据
 * @param {String} prop 当前 prop
 * @return any
 * */
// export function handleRowAccordingToProp(
//   row: Record<string, any>,
//   prop: string
// ): Record<string, any> {
//   if (!prop.includes('.')) return row[prop] ?? '--';
//   prop.split('.').forEach(item => (row = row[item] ?? '--'));
//   return row;
// }
type NestedPartial<T> = {
  [P in keyof T]?: NestedPartial<T[P]> | T[P];
};
export function handleRowAccordingToProp<T extends NestedPartial<Record<string, unknown>>>(
  row: T,
  prop: string
): unknown {
  if (!prop.includes('.')) return (row[prop as keyof T] ?? '--') as unknown;

  let current: unknown = row as Record<string, unknown>; // 这里添加了断言
  for (const item of prop.split('.')) {
    if (typeof current !== 'object' || current === null || !(item in current)) {
      return '--';
    }
    current = current[item as keyof typeof current]; // 这里也添加了断言
  }

  return current;
}
/**
 * @description 处理 prop，当 prop 为多级嵌套时 ==> 返回最后一级 prop
 * @param {String} prop 当前 prop
 * @return string
 * */
export function handleProp(prop: string): string {
  const propArr = prop.split('.');
  if (propArr.length == 1) return prop;
  return propArr[propArr.length - 1];
}

/**
 * @description 根据枚举列表查询当需要的数据（如果指定了 label 和 value 的 key值，会自动识别格式化）
 * @param {String} callValue 当前单元格值
 * @param {Array} enumData 字典列表
 * @param {Array} fieldNames 指定 label && value 的 key 值
 * @param {String} type 过滤类型（目前只有 tag）
 * @return string
 * */
// export function filterEnum(
//   callValue: any,
//   enumData: any[] | undefined,
//   fieldNames?: { label: string; value: string },
//   type?: string
// ): string {
//   const value = fieldNames?.value ?? 'value';
//   const label = fieldNames?.label ?? 'label';
//   let filterData: Record<string, any> = {};
//   if (isArray(enumData)) {
//     if (isArray(callValue)) {
//       filterData = enumData.filter((item: any) => callValue.includes(item[value]))
//     } else {
//       filterData = enumData.find((item: any) => item[value] === String(callValue));
//     }
//   }
//   if (type == 'tag') {
//     if (isArray(filterData)) {
//       filterData = filterData.map(res => {
//         res.tagType = res.tagType ? res.tagType : ''
//         return res
//       })
//     } else {
//       return filterData?.tagType ? filterData.tagType : ''
//     }
//   }

//   if (isArray(filterData)) {
//     return filterData.map(res => res[label]).join(',')
//   } else {
//     return filterData ? filterData[label] : '--';
//   }
// }
export function filterEnum<T extends Record<string, unknown>>(
  callValue: unknown,
  enumData: T[] | undefined,
  fieldNames?: { label: string; value: string },
  type?: string
): string {
  const value = fieldNames?.value ?? 'value';
  const label = fieldNames?.label ?? 'label';

  let filterData: T | T[] | undefined = undefined;
  if (Array.isArray(enumData)) {
    if (Array.isArray(callValue)) {
      filterData = enumData.filter((item) => callValue.includes(item[value]));
    } else {
      filterData = enumData.find((item) => item[value] === String(callValue));
    }
  }

  if (type === 'tag') {
    if (Array.isArray(filterData)) {
      filterData = filterData.map((res) => {
        // 假设T类型具有tagType属性，否则这里需要更具体的类型断言
        (res as { tagType?: string }).tagType = (res as { tagType?: string }).tagType ?? '';
        return res;
      });
    } else if (filterData) {
      // 假设T类型具有tagType属性，否则这里需要更具体的类型断言
      return (filterData as { tagType?: string }).tagType ?? '';
    }
  }

  if (Array.isArray(filterData)) {
    return filterData.map((res) => res[label]).join(',');
  } else if (filterData) {
    return (filterData[label] as string) ?? '--';
  }

  // 如果filterData始终为undefined，则这里会返回undefined，但根据函数签名，这里应该返回一个string
  // 如果需要确保始终返回一个string，可以添加一个默认返回值
  return '--';
}

// 通用导出模板
export function download<T>(url: string, params: T, filename: string): Promise<void> {
  const loadingInstance = ElLoading.service({ text: '正在下载数据，请稍候', background: 'rgba(0, 0, 0, 0.7)' })
  return axios.post(url, params, {
    transformRequest: [(params: T): string => { return tansParams(params as Record<string, unknown>) }],
    headers: { 'Authorization': getToken() },
    responseType: 'arraybuffer'
  }).then((res) => {
    const blob = new Blob([res.data], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const objectUrl = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.style.display = 'none'
    a.href = objectUrl // 指定下载链接
    a.download = filename// 指定下载文件名
    a.click()
    URL.revokeObjectURL(a.href) // 释放URL对象
    loadingInstance.close()
  }).catch(() => {
    loadingInstance.close()
    ElMessage.error('下载文件出现错误，请联系管理员！')
  })
}
// 参数处理
function tansParams(params: Record<string, unknown>): string {
  let result = ''
  for (const propName of Object.keys(params)) {
    const value = params[propName] as string | Record<string, unknown>
    const part = encodeURIComponent(propName) + '='
    if (value !== null && value !== '' && typeof (value) !== 'undefined') {
      if (typeof value === 'object') {
        for (const key of Object.keys(value)) {
          if (value[key] !== null && value[key] !== '' && typeof (value[key]) !== 'undefined') {
            const params = propName + '[' + key + ']'
            const subPart = encodeURIComponent(params) + '='
            result += subPart + encodeURIComponent(value[key] as string) + '&'
          }
        }
      } else {
        result += part + encodeURIComponent(value) + '&'
      }
    }
  }
  return result
}